using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace ServerDiff
{
    public partial class ServerDiffForm : Form
    {
        public ServerDiffForm()
        {
            InitializeComponent();
        }

        private void CompareButton_Click(object sender, EventArgs e)
        {
            CompareButton.Enabled = false;
            OutputTextBox.Text = string.Empty;

            if (string.IsNullOrEmpty(PsInfoPathTextBox.Text) || !File.Exists(PsInfoPathTextBox.Text))
            {
                MessageBox.Show("Please select a valid path for PsInfo");
                return;
            }
            if (ServersTextBox.Lines == null || ServersTextBox.Lines.GetLength(0) < 2)
            {
                MessageBox.Show("Please provide atleast 2 servers you wish to compate");
                return;
            }

            List<string> servers = new List<string>();
            servers.AddRange(ServersTextBox.Lines);
            Application.DoEvents();
            try
            {
                if (AnalyseServers(servers))
                    MessageBox.Show("The servers are all the same");
                else
                    MessageBox.Show("The servers do not all match, refer to the information displayed for more details");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            CompareButton.Enabled = true;
        }
        /// <summary>
        /// Compares the servers using psinfo
        /// </summary>
        /// <param name="computers"></param>
        /// <returns></returns>
        private bool AnalyseServers(List<string> computers)
        {
            string primaryDescription = null;
            bool match = true;

            List<string> descriptions = new List<string>();
            foreach (string server in computers)
            {
                OutputTextBox.Text += Environment.NewLine;
                OutputTextBox.Text += Environment.NewLine;
                OutputTextBox.Text += "Analysing server: " + server;
                OutputTextBox.Text += Environment.NewLine;

                Application.DoEvents();
                string description = RunPsInfo(string.Format(@"\\{0} -h -s", server), Path.GetDirectoryName(PsInfoPathTextBox.Text));
                if (string.IsNullOrEmpty(description))
                    throw new ApplicationException("No description returned from PsInfo, please check the machine names");

                //Remove the machine name identifier at the start
                int index = description.IndexOf("Kernel version:");
                description = description.Substring(index);

                //Remove the installed date
                const string InstallDateFormat = @"Install date:              \d\d/\d\d/\d\d\d\d, \d\d:\d\d:\d\d";
                description = Regex.Replace(description, InstallDateFormat, string.Empty);

                if (string.IsNullOrEmpty(primaryDescription))
                    primaryDescription = description;
                else
                {
                    Application.DoEvents();
                    if (Compare(primaryDescription, description))
                    {
                        OutputTextBox.Text += string.Format("Server {0} and {1} match", computers[0], server);
                        OutputTextBox.Text += Environment.NewLine;
                    }
                    else
                    {
                        OutputTextBox.Text += string.Format("Server {0} and {1} do not match", computers[0], server);
                        OutputTextBox.Text += Environment.NewLine;
                        match = false;
                    }
                    
                }
            }
            return match;
        }
        /// <summary>
        /// Compares the output from the latest analysis with the first server
        /// </summary>
        /// <param name="output"></param>
        /// <param name="expected"></param>
        /// <returns></returns>
        private bool Compare(string output, string expected)
        {
            bool result = true;

            if (output.Length != expected.Length)
            {
                OutputTextBox.Text += "The lengths are not as expected";
                OutputTextBox.Text += Environment.NewLine;
                OutputTextBox.Text += "Output length is " + output.Length.ToString() + " chars"; ;
                OutputTextBox.Text += Environment.NewLine;
                OutputTextBox.Text += "Expected length is " + expected.Length.ToString() + " chars"; ;
                OutputTextBox.Text += Environment.NewLine;
                OutputTextBox.Text += "See below for a comparison of the descriptions"; ;
                OutputTextBox.Text += Environment.NewLine;
                              
                result = false;             
            }

            
                int index = 0;
                for (index = 0; index <= output.Length - 1; index++)
                {
                    if (index > expected.Length - 1)
                        break;

                    char outputChar = output[index];
                    char expectedChar = expected[index];

                    if (!outputChar.Equals(expectedChar))
                    {
                        result = false;
                        break;
                    }
                }
                if (result == false)
                {
                    OutputTextBox.Text += Environment.NewLine;
                    OutputTextBox.Text += "The output file so far is: " + Environment.NewLine + output.Substring(0, index + 1);
                    OutputTextBox.Text += Environment.NewLine;
                    OutputTextBox.Text += Environment.NewLine;
                    OutputTextBox.Text += "The expected file so far is: " + Environment.NewLine + expected.Substring(0, index + 1);
                    OutputTextBox.Text += Environment.NewLine;
                    OutputTextBox.Text += "The char at index " + index.ToString() + " does not match";
                    OutputTextBox.Text += Environment.NewLine;

                    OutputTextBox.Text += Environment.NewLine;
                    OutputTextBox.Text += "The rest of the output file is: " + Environment.NewLine + output.Remove(0, index + 1);
                    OutputTextBox.Text += Environment.NewLine;
                    OutputTextBox.Text += Environment.NewLine;
                    OutputTextBox.Text += "The rest of the expected file is: " + Environment.NewLine + expected.Remove(0, index + 1);
                    OutputTextBox.Text += Environment.NewLine;
                }
            

            return result;
        }        
        /// <remarks />
        private string RunPsInfo(string args, string workingDirectory)
        {
            string output;
            
            ProcessStartInfo processStartInfo = new ProcessStartInfo(PsInfoPathTextBox.Text, args);
            processStartInfo.CreateNoWindow = true;
            processStartInfo.RedirectStandardError = true;
            processStartInfo.RedirectStandardOutput = true;
            processStartInfo.UseShellExecute = false;
            processStartInfo.WorkingDirectory = workingDirectory;
            Process process = Process.Start(processStartInfo);
            output = process.StandardOutput.ReadToEnd();
            process.WaitForExit();            
            return output;
        }

        private void BrowseButton_Click(object sender, EventArgs e)
        {
            openFileDialog1.Title = "Select PsInfo.exe";            
            DialogResult dr = openFileDialog1.ShowDialog();
            if (dr == DialogResult.OK)
            {
                PsInfoPathTextBox.Text = openFileDialog1.FileName;
            }
        }
    }
}